#pragma once
#include <iostream>
#include <string>
#include <cstring>
#include <cstdlib>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>
#include <pthread.h>
#include <functional>
#include "protocol.hpp"
#define NUM 1024
static const uint16_t gport = 8080;
static const int gbacklog = 5;
using namespace std;
namespace Server
{
    enum
    {
        USAGE_ERR = 1,
        SOCK_ERR,
        BIND_ERR,
        LISTEN_ERR
    };
    class httpserver;
    using func_t = function<bool(const HttpRequest &, HttpResponse &)>; // 重定义func_t
    class httpserver
    {
    public:
        httpserver(func_t func, const uint16_t &port = gport) : _port(port), _listensock(-1), _func(func) {}
        void inithttpserver()
        {
            // 1.创建套接字
            _listensock = socket(AF_INET, SOCK_STREAM, 0);
            if (_listensock < 0)
            {
                exit(SOCK_ERR);
            }
            // 2.bind ip和port
            struct sockaddr_in local;
            local.sin_family = AF_INET;
            local.sin_port = htons(_port);
            local.sin_addr.s_addr = INADDR_ANY;
            if (bind(_listensock, (struct sockaddr *)&local, sizeof(local)) < 0) // 绑定失败
            {
                exit(BIND_ERR);
            }
            // 3.将套接字设置为监听模式
            if (listen(_listensock, gbacklog) < 0)
            {
                exit(LISTEN_ERR);
            }
        }

        void HandlerHttp(int sock)
        {
            char buffer[4096];
            HttpRequest req;
            HttpResponse rep;
            // 1.读取到完整报文
            ssize_t n = recv(sock, buffer, sizeof(buffer) - 1, 0); // 大概率能读到完整报文
            if (n > 0)
            {
                buffer[n] = 0;
                req._inbuffer = buffer;
                // 2.req反序列化
                   req.parse();//拿客户端发送来的报文去构建req对象的成员变量
                // 3.调用外部参数
                     _func(req,rep);//
                // 4.rep序列化
                // 5.server send data to client

                 send(sock,rep._outbuffer.c_str(),rep._outbuffer.size(),0);
            }
        }

        void start()
        {
            while (true)
            {
                struct sockaddr_in cli;
                socklen_t len = sizeof(cli);
                bzero(&cli, len);

                int sock = accept(_listensock, (struct sockaddr *)&cli, &len);
                if (sock < 0)
                {
                    continue;
                }

                cout << "accept sock: " << sock << endl;

                // 多进程版---
                pid_t id = fork(); // 创建子进程
                if (id == 0)       // 子进程进入
                {
                    close(_listensock); // 子进程不需要用于监听因此关闭该文件描述符
                    if (fork() > 0)
                        exit(0);

                    // //孙子进程
                    HandlerHttp(sock); // 调用操作函数
                    close(sock);
                    exit(0);
                }
                // 父进程
                close(sock); // 父进程不使用文件描述符就关闭
                waitpid(id, nullptr, 0);
            }
        }

        ~httpserver() {}

    private:
        int _listensock; // 用于监听服务器的sock文件描述符
        uint16_t _port;  // 端口号
        func_t _func;
    };

}